import { defineComponent, watch, markRaw, h, ref, onMounted, provide, onUnmounted } from 'vue';
import { getLngLat } from './mapUtils.js';
import { loadBMap } from './map-loader.js';

/* global BMapGL */

export const CMap = defineComponent({
  name: 'CMap',
  props: {
    useAMap: Boolean,
    useOffline: undefined,
    useOnline: undefined,
    disabled: Boolean,
    config: undefined,
    center: undefined,
    zoom: undefined,
    boundary: undefined,
    styleJson: undefined,
  },
  emits: ['ready'],
  setup(props, { slots, emit, expose }) {
    let style = { position: 'relative', width: '100%', height: '100%', overflow: 'hidden' };
    let id = 'map_' + String(Math.random()).slice(-13) + '_' + Date.now();
    let ready = ref(false);
    let map = null;

    function flyTo(lngLat, zoom) {
      lngLat = getLngLat(lngLat);
      if (!map || !lngLat) {
        return;
      }
      if (Number.isFinite(zoom)) {
        map.flyTo(lngLat, zoom);
      } else {
        map.setViewport([new BMapGL.Point(...lngLat)]);
      }
    }

    async function setMapStyle() {
      if (window.offmapcfg && window.offmapcfg.websidestyle) {
        let options = { method: 'GET', mode: 'cors' };
        let stylejson = await fetch(window.offmapcfg.websidestyle, options).then((r) => r.json());
        if (stylejson) {
          map.setMapStyleV2({ styleJson: stylejson });
        }
      }
    }
    function setMapBoundary(boundaries) {
      if (Array.isArray(boundaries) && boundaries.length) {
        boundaries = boundaries.reduce((res, item) => {
          const points = item.split(';').map((lnglat) => lnglat.split(','));
          const path = points.map(([lng, lat]) => new BMapGL.Point(lng, lat));
          return res.concat(path);
        }, []);
        // this.createMask(boundaries);
        this.addMask(this.map, boundaries);
      }
    }
    function createMask(path) {
      const border = new BMapGL.Polyline(path, {
        strokeColor: '#4ca7a2',
        strokeWeight: 3,
        strokeOpacity: 1,
      });
      const mapMask = new BMapGL.MapMask(path, {
        isBuildingMask: true,
        isPoiMask: true,
        isMapMask: true,
        showRegion: 'inside',
        topFillColor: '#000',
        topFillOpacity: 1,
        sideFillColor: '#000',
        sideFillOpacity: 1,
      });
      this.map.addOverlay(border);
      this.map.addOverlay(mapMask);
    }
    // 添加遮罩
    function addMask(points) {
      if (!Array.isArray(points)) {
        return;
      }
      var maskPoints = [...points];
      var EN_JW = new BMapGL.Point(200, 90); // 东北角
      var NW_JW = new BMapGL.Point(-200, 90); // 西北角
      var WS_JW = new BMapGL.Point(-200, -90); // 西南角
      var SE_JW = new BMapGL.Point(200, -90); // 东南角
      // 添加环形遮罩层
      if (maskPoints.length > 0) {
        maskPoints.push(maskPoints[0]);
      }
      maskPoints.push(EN_JW);
      maskPoints.push(SE_JW);
      maskPoints.push(WS_JW);
      maskPoints.push(NW_JW);
      maskPoints.push(EN_JW);
      const mask = new BMapGL.Polygon(maskPoints, {
        strokeColor: '#0d131e',
        fillColor: '#0d131e',
        /* 遮罩外轮廓会有一条线链接到内轮廓,所以需要设置 strokeOpacity = 0 来隐藏这条线 */
        strokeOpacity: 0,
        fillOpacity: 0.75,
      });
      mask.disableMassClear();
      this.map.addOverlay(mask);
    }

    onMounted(async () => {
      await loadBMap(
        Object.assign({}, props.config, {
          useOffline: props.useOffline,
          useOnline: props.useOnline,
        })
      );
      let center = getLngLat(props.center) || [104.07297778669162, 30.685334863327093];
      let zoom = props.zoom || 12;
      map = markRaw(new BMapGL.Map(id)); // 创建Map实例
      //初始化地图,设置中心点坐标和地图级别
      map.centerAndZoom(new BMapGL.Point(...center), zoom);
      map.setDisplayOptions({ poiIcon: false, poiText: true, indoor: false });
      map.setCopyrightOffset({ width: 1, height: 1 }, { width: 1, height: 1 });

      // window.__bmap = map;

      map.addEventListener('click', (e) => {
        console.log(e);
      });

      if (props.styleJson) {
        map.setMapStyleV2({ styleJson: props.styleJson });
      } else {
        setMapStyle();
      }

      let els = map.container.querySelectorAll('.anchorBL');
      Array.prototype.forEach.call(els, (el) => {
        el.remove();
      });

      watch(
        () => props.disabled,
        (disabled) => {
          if (disabled === true) {
            map.disableDoubleClickZoom();
            map.disableScrollWheelZoom();
            map.disableDragging();
            map.disableKeyboard();
          } else {
            map.enableDoubleClickZoom();
            map.enableScrollWheelZoom();
            map.enableDragging();
            map.enableKeyboard();
          }
        },
        { immediate: true }
      );

      ready.value = true;
      emit('ready', { map });
    });

    onUnmounted(() => {
      map && map.destroy();
      props = slots = emit = style = id = ready = map = null;
    });

    provide('useMap', () => map);

    expose({ map, flyTo });

    return () => {
      return h('div', { style: { ...style } }, [
        h('div', { id, style: { ...style, zIndex: 0 } }),
        ready.value === true && typeof slots.default === 'function' ? slots.default({ map }) : null,
      ]);
    };
  },
});
